package pt.isel.pdm.ouryamba;

import java.util.List;

import winterwell.jtwitter.Twitter;
import android.os.Bundle;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

public class TimelineActivity extends BaseActivity implements OnItemClickListener, IMyListener, Runnable
{
		
	private ListView timeLineLayout;
	private DetailFragment detailFragment;
	private Intent refreshIntent;
	private Twitter.Status[] timeLineArray;
	private ArrayAdapter<Twitter.Status> myListAdapter;
	public final static String ID = TimelineActivity.class.getName();
	private final Integer onSuccessToken = 3;
	private static final Integer DETAIL_FRAGMENT_TOKEN = 0;

//Own methods
	
	/**
	 * Refreshes the timeline listview with recent statuses.
	 * 
	 * First set the the selected status position to zero because we don't know which value was 
	 * before. Then displays the "refreshing" state on the listview giving the user the sense
	 * that something is going on.
	 * Later, if the detail fragment exists (layout is in landscape) the views of the detail
	 * fragment are also updated like the listview was.
	 * A reference to this activity is stored in the {@code toNotifyList} of the General class
	 * to guarantee the service will notify this instance the timeline is updated.
	 * The intent is prepared (added the token of this activity) and sent to the service.
	 * 
	 * Why the detail fragment token is not sent also?
	 * First, because only in landscape exists the detail fragment.
	 * Second, the service is not prepared to fetch two tokens from the intent.
	 * 
	 * @see #displayRefreshingState()
	 * @see DetailFragment#updateViewElements(boolean)
	 * */
	private void refreshTimeline()
	{
		app.statusSelectedPosition = 0;
		displayRefreshingState();
		if(detailFragment != null)
		{
			detailFragment.updateViewElements(true);
		}
		app.toNotifyList.add(this);
		if(refreshIntent == null)
		{
			refreshIntent = new Intent(this, TimelinePullService.class);
		}
		refreshIntent.putExtra(TimelinePullService.ARG_TOKEN, onSuccessToken);
		startService(refreshIntent);
		refreshIntent.removeExtra(TimelinePullService.ARG_TOKEN);
	}
	
	/**
	 * Updates the timeline listview so the "refreshing" state is noticed by the user.
	 * */
	@SuppressWarnings("deprecation")
	private void displayRefreshingState()
	{
		Twitter.Status[] resfreshingStatus = new Twitter.Status[1];
		resfreshingStatus[0] = new Twitter.Status(null, getString(R.string.refreshing), 0);
		timeLineLayout.setAdapter(new ArrayAdapter<Twitter.Status>(getApplicationContext(),
				android.R.layout.simple_list_item_1, resfreshingStatus));
	}
	

//Activity methods
	
	/**
	 * Stores a reference to the list view of this layout and start the automatic update task on the
	 * General class if is that the user intention (through the value in the preferences).
	 * 
	 * Append one listener to the listview and sign that to this instance so when the status is
	 * clicked, the code executed is from this class ({@code onItemClick()} method).
	 * If the preference option about automatic updates is enable, the task which performs that work
	 * is started from here ({@code General.startAutomaticUpdate()}).
	 * 
	 * @see General#getAutomaticUpdate()
	 * @see General#startAutomaticUpdate()
	 * */
	@Override
	public void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_timeline);
		timeLineLayout = (ListView)findViewById(R.id.timelineListView);
		timeLineLayout.setClickable(true);
		timeLineLayout.setOnItemClickListener(this);
		if(app.getAutomaticUpdate())
		{
			app.startAutomaticUpdate();
		}
	}
	
	/**
	 * Updates the views that are interested on this callback.
	 * 
	 * The views from detail fragment can be interested on this callback also if the device is in
	 * landscape mode for example.
	 * So every time this activity is in focus the views from this activity and detail fragment
	 * (if in landscape) are updated.
	 * Here is also set the {@code statusSelectedPosition} variable to zero because if the device
	 * is in landscape, this will be the position of the status which it's detail will be show by
	 * default. The statement could be surrounded by an {@code if} scope but there is not much
	 * impact leaving it like that.
	 * 
	 * Here is where the reference for detail fragment will be stored if was not already and is
	 * found.
	 * The kind of refresh can behave in two ways. If is the first time on application lifetime that
	 * this activity is shown (second {@code if} scope), the call to {@code refreshTimeline()} is
	 * performed so the statuses could be fetched from the server.
	 * Otherwise ({@code else} scope), the activity was already shown and the statuses are seized
	 * in the timeline private list of status. That way we only need to update the listview with the
	 * statuses from that list.
	 * 
	 * @see #refreshTimeline()
	 * @see DetailFragment#updateViewElements(boolean)
	 * */
	@Override
	public void onResume()
	{
		app.statusSelectedPosition = 0;
		if(findViewById(R.id.detailFragment) != null)
		{
			detailFragment = (DetailFragment) getFragmentManager().findFragmentById(R.id.detailFragment);
		}
		if(myListAdapter == null)
		{
			refreshTimeline();
		}
		else
		{
			timeLineLayout.setAdapter(myListAdapter);
			if(detailFragment != null)
			{
				detailFragment.updateViewElements(false);
			}
		}
		super.onResume();
	}

	/**
	 * Delegates the behavior for each menu item when it's clicked.
	 * 
	 * When the item clicked is the status option, the action is to open the StatusActivity.
	 * However, we added the flag {@code FLAG_ACTIVITY_REORDER_TO_FRONT} to the intent to avoid
	 * creating multiple activities of the same type. With this, if an activity is already in the
	 * background of this back stack, the desired activity will be brought to front instead of being
	 * created again.
	 * 
	 * When the item clicked is the refresh option, the action is to call the method refreshTimeline()
	 * of this class.
	 * 
	 * If the item clicked is not a responsibility of this activity, the decision is given to the
	 * BaseActivity with the {@code super} call on the default closure.
	 * 
	 * @see #refreshTimeline()
	 * @see BaseActivity#onOptionsItemSelected(MenuItem)
	 * */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) 
	{
		switch(item.getItemId())
		{
			case R.id.action_status:
				startActivity(new Intent(this, StatusActivity.class)
					.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
				return true;
			case R.id.action_refresh:
				refreshTimeline();
				return true;
			default:
				return super.onOptionsItemSelected(item);
		}
	}	
	
	/**
   	 * Sets some menu items invisible (the ones that don't matter for this Activity).
   	 * 
   	 * Hide the timeline menu item because there is none sense having that here.
   	 * */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.shared_menu, menu);
		menu.getItem(1).setVisible(false);
		return true;
	}
	
	/**
	 * Stops the TimelinePullService service if it was ever started.
	 * 
	 * Just checks if the intent for the service was ever created and if so stops it with the same
	 * intent and set it to null (helping GC).
	 * */
	@Override
	public void onDestroy()
	{
		if(refreshIntent != null)
		{
   			stopService(refreshIntent);
   			refreshIntent = null;
		}
		super.onDestroy();
	}
	
	
//OnItemClickListener methods
	
	/**
	 * Delegates the behavior when some item in the list is clicked.
	 * 
	 * When some item is clicked, we store the status that was clicked inside the General 
	 * class, so when the DetailActivity is created (or the detail fragment updated) the value
	 * can be fetched from there.
	 * After, we send one intent to start the activity DetailActivity.
	 * 
	 * @see DetailFragment#updateViewElements(boolean)
	 * */
	@Override
	public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) 
	{
		app.statusSelectedPosition = position;
		if(detailFragment == null)
		{
			startActivity(new Intent(getApplicationContext(), DetailActivity.class));			
		}
		else
		{
			detailFragment.updateViewElements(false);
		}
	}

	
//IMyListener methods
	
	/**
	 * Performs some actions due to the service execution success.
	 * 
	 * Since the call to this method will be done by one thread from the service (not the UI thread)
	 * we need to delegate some actions to be taken in the UI thread.
	 * 
	 * So we use one Runnable type to define those actions and we send that Runnable to be ran on
	 * the UI thread, with the {@code runOnUiThread(this)} call.
	 * We use this class to implement the Runnable method ({@code run()}) so the Java VM won't create
	 * another class for this simple method implementation.
	 * 
	 * When the service successfully fetches the statuses, the listview should be updated with the
	 * fresh statuses.
	 * 
	 * @see DetailFragment#onSuccess(Integer)
	 * */
	@Override
	public void onSuccess(Integer token)
	{
		if(token != onSuccessToken)
		{
			return;
		}
		if(detailFragment != null)
		{
			detailFragment.onSuccess(DETAIL_FRAGMENT_TOKEN);
		}
		runOnUiThread(this);
	}

	
//Runnable methods
	
	/**
	 * Updates the views of the TimelineActivity with the new statuses.
	 * 
	 * First removes the reference of this instance from the {@code General.toNotifyList}. Then
	 * limits the number of status to show according to the correspondent preference value and updates
	 * the timeline list view with that range of statuses.
	 * 
	 * @see General#getMaxMsgStored()
	 * @see General#getMaxMsgToShow()
	 * */
	@Override
	public void run()
	{
		app.toNotifyList.remove(this);
		List<Twitter.Status> list = app.listOfStatuses;
		int msgToShow;
		if(app.getMaxMsgStored() < app.getMaxMsgToShow())
		{
			msgToShow = app.getMaxMsgStored();
		}
		else
		{
			msgToShow = app.getMaxMsgToShow();
		}
		if(msgToShow > list.size())
		{
			msgToShow = list.size();
		}
		list = list.subList(0, msgToShow);
		timeLineArray = list.toArray(new Twitter.Status[list.size()]);								
		myListAdapter = new ArrayAdapter<Twitter.Status>(getApplicationContext(),
			        android.R.layout.simple_list_item_1, timeLineArray );
		timeLineLayout.setAdapter(myListAdapter);
	}
}
